package com.mall.user.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mall.model.vo.UserStatsVO;
import com.mall.user.common.exception.BusinessException;
import com.mall.user.common.response.ResultCode;
import com.mall.user.constant.CommonConstant;
import com.mall.user.mapper.UserMapper;
import com.mall.user.model.dto.user.UserQueryRequest;
import com.mall.user.model.entity.User;
import com.mall.user.model.vo.LoginUserVO;
import com.mall.user.model.vo.UserVO;
import com.mall.user.service.UserFavoriteService;
import com.mall.user.service.UserService;
import com.mall.user.utils.SqlUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.mall.user.constant.UserConstant.USER_LOGIN_STATE;

/**
* @author 张云博
* @description 针对表【user(用户表)】的数据库操作Service实现
* @createDate 2025-08-29 10:04:36
*/

@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private UserFavoriteService userFavoriteService;
    
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    @Transactional
    public long userRegister(String userName, String userPassword, String checkPassword) {
        // 1. 校验
        if (!userPassword.equals(checkPassword)) {
            throw new BusinessException(ResultCode.PARAMS_ERROR, "两次输入的密码不一致");
        }
        synchronized (userName.intern()) {
            // 账户不能重复
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("username", userName);
            long count = userMapper.selectCount(queryWrapper);
            if (count > 0) {
                throw new BusinessException(ResultCode.PARAMS_ERROR, "账号重复");
            }
            // 2. 加密
            String encryptPassword = passwordEncoder.encode(userPassword);
            // 3. 插入数据
            User user = new User();
            user.setUsername(userName);
            user.setPassword(encryptPassword);
            boolean saveResult = this.save(user);
            if (!saveResult) {
                throw new BusinessException(ResultCode.SYSTEM_ERROR, "注册失败");
            }
            return user.getId();
        }
    }

    @Override
    public LoginUserVO userLogin(String userAccount, String userPassword, HttpServletRequest request) {
        // 1. 校验
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new BusinessException(ResultCode.PARAMS_ERROR, "参数为空");
        }
        // 2. 查询用户 - 支持用户名/手机号/邮箱登录
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.and(wrapper -> wrapper
                .eq("username", userAccount)
                .or().eq("phone", userAccount)
                .or().eq("email", userAccount)
        );
        User user = userMapper.selectOne(queryWrapper);
        // 用户不存在
        if (user == null) {
            throw new BusinessException(ResultCode.PARAMS_ERROR, "用户不存在或密码错误");
        }
        // 3. 校验密码
        String encryptPassword = user.getPassword();
        if (!passwordEncoder.matches(userPassword, encryptPassword)) {
            throw new BusinessException(ResultCode.PARAMS_ERROR, "用户不存在或密码错误");
        }
        // 4. 更新最后登录时间和登录次数
        user.setLast_login_time(LocalDateTime.now());
        user.setLogin_times(user.getLogin_times() == null ? 1 : user.getLogin_times() + 1);
        this.updateById(user);
        
        // 5. 记录用户的登录态，便于网关过滤器读取
        Map<String, Object> userInfoMap = convertUserToMap(user);
        request.getSession().setAttribute(USER_LOGIN_STATE, userInfoMap);
        
        // 6. 根据用户类型设置动态TTL
        setDynamicSessionTTL(request, user);
        
        return this.getLoginUserVO(user);
    }

    /**
     * 将User对象转换为Map，便于网关过滤器读取
     */
    private Map<String, Object> convertUserToMap(User user) {
        Map<String, Object> userMap = new HashMap<>();
        userMap.put("id", user.getId());
        userMap.put("username", user.getUsername());
        userMap.put("user_type", user.getUser_type());
        return userMap;
    }

    @Override
    public User getLoginUser(HttpServletRequest request) {
        // 先判断是否已登录
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        if (userObj == null) {
            throw new BusinessException(ResultCode.NOT_LOGIN_ERROR);
        }
        
        User currentUser;
        // 处理Session中存储的Map格式用户信息
        if (userObj instanceof Map) {
            Map<String, Object> userMap = (Map<String, Object>) userObj;
            Long userId = (Long) userMap.get("id");
            if (userId == null) {
                throw new BusinessException(ResultCode.NOT_LOGIN_ERROR);
            }
            // 从数据库查询最新用户信息
            currentUser = this.getById(userId);
        } else if (userObj instanceof User) {
            currentUser = (User) userObj;
        } else {
            throw new BusinessException(ResultCode.NOT_LOGIN_ERROR);
        }
        
        if (currentUser == null || currentUser.getId() == null) {
            throw new BusinessException(ResultCode.NOT_LOGIN_ERROR);
        }
        
        return currentUser;
    }

    @Override
    public boolean userLogout(HttpServletRequest request) {
        if (request.getSession().getAttribute(USER_LOGIN_STATE) == null) {
            throw new BusinessException(ResultCode.NOT_LOGIN_ERROR, "未登录");
        }
        try {
            String sessionId = request.getSession().getId();
            String sessionKey = "mall:session:sessions:" + sessionId;
            // 使当前会话立即失效
            request.getSession().invalidate();
            // 清理 Redis 中对应的 Session 数据
            redisTemplate.delete(sessionKey);
            log.info("用户登出，已失效会话并清理Redis会话: {}", sessionKey);
        } catch (Exception e) {
            log.warn("登出时清理会话失败: {}", e.getMessage());
        }
        return true;
    }

    @Override
    @Transactional
    public boolean updatePasswordById(Long userId, String encodedPassword) {
        return this.lambdaUpdate()
                .set(User::getPassword, encodedPassword)
                .eq(User::getId, userId)
                .update();
    }

    @Override
    public LoginUserVO getLoginUserVO(User user) {
        if (user == null) {
            return null;
        }
        LoginUserVO loginUserVO = new LoginUserVO();
        
        BeanUtils.copyProperties(user, loginUserVO);
        
        loginUserVO.setUserType(user.getUser_type());
        loginUserVO.setUserLevel(user.getUser_level());
        loginUserVO.setTotalSpent(user.getTotal_spent());
        loginUserVO.setCurrentYearSpent(user.getCurrent_year_spent());
        loginUserVO.setOrderCount(user.getOrder_count());
        loginUserVO.setLevelUpgradeTime(user.getLevel_upgrade_time());
        loginUserVO.setLoginTimes(user.getLogin_times());
        loginUserVO.setLastLoginTime(user.getLast_login_time());
        loginUserVO.setCreatedTime(user.getCreated_time());
        loginUserVO.setUpdateTime(user.getUpdate_time());
        
        return loginUserVO;
    }

    @Override
    public UserVO getUserVO(User user) {
        if (user == null) {
            return null;
        }
        
        // 检查并自动更新会员等级
        checkAndUpdateUserLevel(user);
        
        UserVO userVO = new UserVO();
        
        BeanUtils.copyProperties(user, userVO);
        
        userVO.setUserType(user.getUser_type());
        userVO.setUserLevel(user.getUser_level());
        userVO.setTotalSpent(user.getTotal_spent());
        userVO.setCurrentYearSpent(user.getCurrent_year_spent());
        userVO.setOrderCount(user.getOrder_count());
        userVO.setLevelUpgradeTime(user.getLevel_upgrade_time());
        userVO.setLoginTimes(user.getLogin_times());
        userVO.setLastLoginTime(user.getLast_login_time());
        userVO.setCreatedTime(user.getCreated_time());
        userVO.setUpdateTime(user.getUpdate_time());
        
        return userVO;
    }

    @Override
    public List<UserVO> getUserVO(List<User> userList) {
        if (CollUtil.isEmpty(userList)) {
            return new ArrayList<>();
        }
        return userList.stream().map(this::getUserVO).collect(Collectors.toList());
    }
    
    /**
     * 检查并自动更新用户会员等级
     */
    private void checkAndUpdateUserLevel(User user) {
        if (user == null || user.getTotal_spent() == null) {
            return;
        }
        
        // 根据累计消费金额计算应有等级
        Integer currentLevel = user.getUser_level();
        Integer targetLevel = calculateUserLevel(user.getTotal_spent());
        
        // 如果等级需要更新
        if (!targetLevel.equals(currentLevel)) {
            log.info("用户 {} 等级需要更新: {} -> {}, 累计消费: {}", 
                user.getUsername(), currentLevel, targetLevel, user.getTotal_spent());
            
            // 更新数据库中的会员等级
            user.setUser_level(targetLevel);
            user.setLevel_upgrade_time(LocalDateTime.now());
            this.updateById(user);
            
            log.info("用户 {} 等级已自动更新为: {}", user.getUsername(), targetLevel);
        }
    }
    
    /**
     * 根据消费金额计算会员等级
     */
    private Integer calculateUserLevel(BigDecimal totalSpent) {
        if (totalSpent == null || totalSpent.compareTo(BigDecimal.ZERO) <= 0) {
            return 2; // 普通会员
        }
        
        BigDecimal blackGoldThreshold = new BigDecimal("50000.00");
        BigDecimal platinumThreshold = new BigDecimal("10000.00");
        
        if (totalSpent.compareTo(blackGoldThreshold) >= 0) {
            return 0; // 黑金会员
        } else if (totalSpent.compareTo(platinumThreshold) >= 0) {
            return 1; // 白金会员
        } else {
            return 2; // 普通会员
        }
    }

    @Override
    public QueryWrapper<User> getQueryWrapper(UserQueryRequest userQueryRequest) {
        if (userQueryRequest == null) {
            throw new BusinessException(ResultCode.PARAMS_ERROR, "请求参数为空");
        }

        Long id = userQueryRequest.getId();
        String username = userQueryRequest.getUsername();
        String userType = userQueryRequest.getUserType();
        Integer memberLevel = userQueryRequest.getUserLevel();
        Integer enabled = userQueryRequest.getEnabled();
        LocalDateTime createdTime = userQueryRequest.getCreatedTime();
        String sortField = userQueryRequest.getSortField();
        String sortOrder = userQueryRequest.getSortOrder();

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();

        // 精确查询条件
        queryWrapper.eq(id != null, "id", id);
        queryWrapper.eq(StringUtils.isNotBlank(userType), "user_type", userType);
        queryWrapper.eq(memberLevel != null, "member_level", memberLevel);
        queryWrapper.eq(enabled != null, "enabled", enabled);

        // 模糊查询条件
        queryWrapper.like(StringUtils.isNotBlank(username), "username", username);
        
        // 时间查询 - 注册时间
        queryWrapper.eq(createdTime != null, "created_time", createdTime);

        // 排序条件
        queryWrapper.orderBy(SqlUtils.validSortField(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);

        return queryWrapper;
    }

    @Override
    public UserStatsVO getUserStats() {
        UserStatsVO stats = new UserStatsVO();
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime todayStart = LocalDate.now().atStartOfDay();
        
        // 总用户数
        stats.setTotalUsers(this.count());
        
        // 今日新用户数
        QueryWrapper<User> newUserQuery = new QueryWrapper<>();
        newUserQuery.ge("created_time", todayStart);
        stats.setNewUsers(this.count(newUserQuery));
        
        // 今日活跃用户数(今日登录)
        QueryWrapper<User> activeUserQuery = new QueryWrapper<>();
        activeUserQuery.ge("last_login_time", todayStart);
        stats.setActiveUsers(this.count(activeUserQuery));
        
        // 性别分布
        Map<Integer, Long> genderMap = new HashMap<>();
        for (int i = 0; i <= 2; i++) {
            QueryWrapper<User> genderQuery = new QueryWrapper<>();
            genderQuery.eq("sex", i);
            genderMap.put(i, this.count(genderQuery));
        }
        stats.setGenderDistribution(genderMap);
        
        // 会员等级分布
        Map<Integer, Long> memberMap = new HashMap<>();
        for (int i = 0; i <= 2; i++) {
            QueryWrapper<User> memberQuery = new QueryWrapper<>();
            memberQuery.eq("member_level", i);
            memberMap.put(i, this.count(memberQuery));
        }
        stats.setUserLevelDistribution(memberMap);
        
        // 收藏统计
        stats.setTotalFavorites(userFavoriteService.getTotalFavoriteCount());
        stats.setTodayFavorites(userFavoriteService.getTodayFavoriteCount());
        
        // 消费统计
        List<User> users = this.list();
        BigDecimal totalConsumption = users.stream()
                .filter(user -> user.getTotal_spent() != null)
                .map(User::getTotal_spent)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal currentYearConsumption = users.stream()
                .filter(user -> user.getCurrent_year_spent() != null)
                .map(User::getCurrent_year_spent)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        
        stats.setTotalConsumption(totalConsumption);
        stats.setCurrentYearConsumption(currentYearConsumption);
        stats.setStatsTime(now);
        
        return stats;
    }
    
    /**
     * 根据用户类型设置动态Session TTL
     */
    private void setDynamicSessionTTL(HttpServletRequest request, User user) {
        try {
            String sessionId = request.getSession().getId();
            String sessionKey = "mall:session:sessions:" + sessionId;
            String userType = user.getUser_type();
            
            // 封号用户直接删除Session
            if ("ban".equals(userType)) {
                redisTemplate.delete(sessionKey);
                log.warn("封号用户 {} 尝试登录，已删除Session", user.getUsername());
                return;
            }
            
            // 其他用户根据类型计算TTL
            int ttlSeconds = calculateSessionTTL(user);
            
            // 设置Redis中Session的TTL
            redisTemplate.expire(sessionKey, ttlSeconds, TimeUnit.SECONDS);
            
            log.info("用户 {} 登录成功，设置Session TTL: {} 秒", user.getUsername(), ttlSeconds);
            
        } catch (Exception e) {
            log.error("设置动态Session TTL失败: ", e);
        }
    }
    
    /**
     * 根据用户类型计算Session TTL
     */
    private int calculateSessionTTL(User user) {
        String userType = user.getUser_type();
        
        if ("admin".equals(userType)) {
            // 管理员: 1小时
            return 60 * 60;
        } else {
            // 普通用户: 2小时
            return 2 * 60 * 60;
        }
    }

    /**
     * 扣减用户消费金额（用于退款）
     */
    @Override
    @Transactional
    public boolean deductAccountBalance(Long memberId, BigDecimal totalPay) {
        if (memberId == null || totalPay == null || totalPay.compareTo(BigDecimal.ZERO) <= 0) {
            log.warn("扣减用户消费金额参数无效: memberId={}, totalPay={}", memberId, totalPay);
            return false;
        }

        try {
            User user = this.getById(memberId);
            if (user == null) {
                log.error("用户不存在: memberId={}", memberId);
                return false;
            }

            // 计算扣减后的金额，确保不为负数
            BigDecimal currentTotalSpent = user.getTotal_spent() != null ? user.getTotal_spent() : BigDecimal.ZERO;
            BigDecimal currentYearSpent = user.getCurrent_year_spent() != null ? user.getCurrent_year_spent() : BigDecimal.ZERO;
            
            BigDecimal newTotalSpent = currentTotalSpent.subtract(totalPay);
            BigDecimal newYearSpent = currentYearSpent.subtract(totalPay);
            
            // 确保扣减后不为负数
            if (newTotalSpent.compareTo(BigDecimal.ZERO) < 0) {
                newTotalSpent = BigDecimal.ZERO;
            }
            if (newYearSpent.compareTo(BigDecimal.ZERO) < 0) {
                newYearSpent = BigDecimal.ZERO;
            }

            // 更新用户消费金额
            user.setTotal_spent(newTotalSpent);
            user.setCurrent_year_spent(newYearSpent);
            user.setUpdate_time(LocalDateTime.now());
            
            boolean result = this.updateById(user);
            if (result) {
                log.info("成功扣减用户消费金额: memberId={}, totalPay={}, 累计消费: {} -> {}, 今年消费: {} -> {}", 
                    memberId, totalPay, currentTotalSpent, newTotalSpent, currentYearSpent, newYearSpent);
            }
            return result;
        } catch (Exception e) {
            log.error("扣减用户消费金额失败: memberId={}, totalPay={}", memberId, totalPay, e);
            return false;
        }
    }

    /**
     * 增加用户消费金额（用于支付）
     */
    @Override
    @Transactional
    public boolean addAccountBalance(Long memberId, BigDecimal totalPay) {
        if (memberId == null || totalPay == null || totalPay.compareTo(BigDecimal.ZERO) <= 0) {
            log.warn("增加用户消费金额参数无效: memberId={}, totalPay={}", memberId, totalPay);
            return false;
        }

        try {
            User user = this.getById(memberId);
            if (user == null) {
                log.warn("用户不存在: memberId={}", memberId);
                return false;
            }

            // 计算增加后的金额
            BigDecimal currentTotalSpent = user.getTotal_spent() != null ? user.getTotal_spent() : BigDecimal.ZERO;
            BigDecimal currentYearSpent = user.getCurrent_year_spent() != null ? user.getCurrent_year_spent() : BigDecimal.ZERO;
            
            BigDecimal newTotalSpent = currentTotalSpent.add(totalPay);
            BigDecimal newYearSpent = currentYearSpent.add(totalPay);

            // 更新用户消费金额
            user.setTotal_spent(newTotalSpent);
            user.setCurrent_year_spent(newYearSpent);
            user.setUpdate_time(LocalDateTime.now());
            
            boolean result = this.updateById(user);
            if (result) {
                log.info("成功增加用户消费金额: memberId={}, totalPay={}, 累计消费: {} -> {}, 今年消费: {} -> {}", 
                    memberId, totalPay, currentTotalSpent, newTotalSpent, currentYearSpent, newYearSpent);
            }
            return result;
        } catch (Exception e) {
            log.error("增加用户消费金额失败: memberId={}, totalPay={}", memberId, totalPay, e);
            return false;
        }
    }

}